package com.wzcl.app.service.impl;

import com.wzcl.app.dao.model.AppRole;
import com.wzcl.app.dao.model.AppUser;
import com.wzcl.app.dao.model.Grade;
import com.wzcl.app.dao.model.UserInfo;
import com.wzcl.app.dao.repository.AppRoleRepository;
import com.wzcl.app.dao.repository.AppUserRepository;
import com.wzcl.app.model.common.BusinessException;
import com.wzcl.app.model.common.CodeMsg;
import com.wzcl.app.model.common.MyPage;
import com.wzcl.app.model.common.WZCL;
import com.wzcl.app.model.dto.UserDto;
import com.wzcl.app.service.CourseTeacherService;
import com.wzcl.app.service.GradeService;
import com.wzcl.app.service.UserInfoService;
import com.wzcl.app.service.UserService;
import com.wzcl.app.utils.CheckUtil;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;

@Log4j2
@Service
@Transactional
public class UserServiceImpl implements UserService {

    @Autowired
    private AppUserRepository repository;

    @Autowired
    private AppRoleRepository roleRepository;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private UserInfoService userInfoService;

    @Autowired
    private GradeService gradeService;

    @Autowired
    private CourseTeacherService courseTeacherService;

    @Override
    public AppUser registerUser(UserDto userDto) {
        if (userDto == null || StringUtils.isBlank(userDto.getPhone())) {
            throw new BusinessException(CodeMsg.MUST_BE_NOT_NULL, "缺少手机号");
        }
        //正则校验
        /*if (!CheckUtil.phoneCheck(userDto.getPhone())) {
            System.out.println("嘿嘿嘿");
            throw new BusinessException(CodeMsg.SYSTEM_ERR, "手机格式不正确");
        }*/
        AppUser appUser = repository.findByPhone(userDto.getPhone());
        if (appUser != null) {
            throw new BusinessException(CodeMsg.USER_NOT_REPEAT);
        }
        AppUser user = new AppUser();
        BeanUtils.copyProperties(userDto, user, "password", "state", "userState", "type");
        //加密密码
        user.setPassword(passwordEncoder.encode(userDto.getPassword()));
        //生成用户名--->真对手机注册用户生成用户名
        if (StringUtils.isBlank(user.getNickName())) {
            user.setNickName(getStringRandom(8));
        }
        if (userDto.getGradeId() != null) {
            user.setGrade(gradeService.getGradeById(userDto.getGradeId()));
        }
        //默认添加学生权限
        AppRole appRole = roleRepository.findByName("ROLE_STUDENT");
        ArrayList<AppRole> roles = new ArrayList<>();
        roles.add(appRole);
        user.setRoleList(roles);
        user.setType(WZCL.USER_TYPE.STUDENT);
        //添加用户详情
        if (userDto.getUserInfoDto() != null) {
            UserInfo userInfo = userInfoService.addUserInfo(userDto.getUserInfoDto());
            user.setUserInfo(userInfo);
        }
        user.setScore(new BigDecimal("0"));
        user.setUserState(WZCL.USER_STATE.EFFECTIVE);
        user.setState(WZCL.STATE.NOT_DELETE);
        return repository.save(user);
    }

    @Override
    public AppUser addUser(UserDto userDto) {
        //正则校验
        /*if (!CheckUtil.phoneCheck(userDto.getPhone())) {
            throw new BusinessException(CodeMsg.SYSTEM_ERR, "手机格式不正确");
        }*/
        AppUser appUser = repository.findByPhone(userDto.getPhone());
        if (appUser != null) {
            throw new BusinessException(CodeMsg.USER_NOT_REPEAT);
        }
        AppUser user = new AppUser();
        BeanUtils.copyProperties(userDto, user, "password", "state", "userState", "type");
        //加密密码
        user.setPassword(passwordEncoder.encode(userDto.getPassword()));
        //设置权限
        if (userDto.getRoleId() == null) {
            AppRole appRole = roleRepository.findByName("ROLE_STUDENT");
            ArrayList<AppRole> roles = new ArrayList<>();
            roles.add(appRole);
            user.setType(WZCL.USER_TYPE.STUDENT);
            user.setRoleList(roles);
        } else {
            updateUserRole(userDto.getRoleId(), user);
        }
        //添加用户详情
        if (userDto.getUserInfoDto() != null) {
            UserInfo userInfo = userInfoService.addUserInfo(userDto.getUserInfoDto());
            user.setUserInfo(userInfo);
        }
        if (userDto.getGradeId() != null) {
            user.setGrade(gradeService.getGradeById(userDto.getGradeId()));
        }
        user.setScore(new BigDecimal("0"));
        user.setUserState(WZCL.USER_STATE.EFFECTIVE);
        user.setState(WZCL.STATE.NOT_DELETE);
        return repository.save(user);
    }

    @Override
    public AppUser getUserById(Integer id) {
        return repository.findById(id).orElse(null);
    }

    @Override
    public List<AppUser> getUserById(List<Integer> ids) {
        return repository.findAllById(ids);
    }

    @Override
    public List<AppUser> getUserList(UserDto userDto) {
        return repository.findAll(getSpecification(userDto), userDto.getSort());
    }

    @Override
    public MyPage<AppUser> getUserPage(UserDto userDto) {
        Page<AppUser> all = repository.findAll(getSpecification(userDto), userDto.getPageable());
        //将List转换为ArrayList
        ArrayList<AppUser> list = new ArrayList<>(all.getContent());
        Collections.reverse(list);
        MyPage<AppUser> myPage = new MyPage<>();
        myPage.setTotalElements(all.getTotalElements());
        myPage.setContent(list);
        return myPage;
    }

    @Override
    public AppUser updateUser(UserDto userDto) {
        if (userDto == null || userDto.getId() == null) {
            throw new BusinessException(CodeMsg.MUST_BE_NOT_NULL, "缺少用户Id");
        }
        AppUser user = getUserById(userDto.getId());
        if (user == null) {
            throw new BusinessException(CodeMsg.USER_NOT_EXIST);
        }
        BeanUtils.copyProperties(userDto, user, "id", "phone", "state", "type", "userState", "password", "realName");
        //详情
        if (userDto.getUserInfoDto() != null) {
            UserInfo userInfo = userInfoService.updateUserInfo(userDto.getUserInfoDto());
            user.setUserInfo(userInfo);
        }
        //修改年级
        if (userDto.getGradeId() != null && (user.getGrade() == null || !userDto.getGradeId().equals(user.getGrade().getId()))) {
            Grade grade = gradeService.getGradeById(userDto.getGradeId());
            if (grade == null) {
                throw new BusinessException(CodeMsg.GRADE_NOT_EXIST);
            }
            user.setGrade(grade);
        }
        AppUser save = repository.save(user);
        //老师用户同步更新课程老师数据
        if (WZCL.USER_TYPE.TEACHER.equals(save.getType())) {
            courseTeacherService.refreshTeacher(save);
        }
        return save;
    }


    @Override
    public AppUser saveUser(AppUser user) {
        return repository.save(user);
    }

    @Override
    public AppUser getUserByPhone(String phone) {
        return repository.findByPhone(phone);
    }

    @Override
    public AppUser editPwd(UserDto userDto) {
        if (userDto == null || StringUtils.isBlank(userDto.getPhone()) || StringUtils.isBlank(userDto.getPassword())) {
            throw new BusinessException(CodeMsg.MUST_BE_NOT_NULL);
        }
        return editPwd(userDto.getPhone(), userDto.getPassword());
    }

    /**
     * 修改密码专用接口
     *
     * @param phone
     * @param password
     * @return
     */
    @Override
    public AppUser editPwd(String phone, String password) {
        AppUser appUser = repository.findByPhone(phone);
        if (appUser == null) {
            throw new BusinessException(CodeMsg.USER_NOT_EXIST);
        }
        appUser.setPassword(passwordEncoder.encode(password));
        appUser = repository.save(appUser);
        log.info("{}账号修改密码成功", phone);
        return appUser;
    }

    //设置年级
    @Override
    public AppUser changeUserGrade(UserDto userDto) {
        if (userDto.getGradeId() == null) {
            throw new BusinessException(CodeMsg.MUST_BE_NOT_NULL, "缺少年级Id");
        }
        if (userDto.getPhone() == null) {
            throw new BusinessException(CodeMsg.MUST_BE_NOT_NULL, "缺少用户账号");
        }
        AppUser user = getUserByPhone(userDto.getPhone());
        if (user == null) {
            throw new BusinessException(CodeMsg.USER_NOT_EXIST);
        }
        Grade grade = gradeService.getGradeById(userDto.getGradeId());
        if (grade == null) {
            throw new BusinessException(CodeMsg.GRADE_NOT_EXIST);
        }
        user.setGrade(grade);
        return repository.save(user);
    }

    //设置年级
    @Override
    public AppUser changeRealName(UserDto userDto) {
        if (userDto.getPhone() == null) {
            throw new BusinessException(CodeMsg.MUST_BE_NOT_NULL, "缺少用户账号");
        }
        if (StringUtils.isBlank(userDto.getRealName())) {
            throw new BusinessException(CodeMsg.MUST_BE_NOT_NULL, "缺少用户姓名");
        }
        AppUser user = getUserByPhone(userDto.getPhone());
        if (user == null) {
            throw new BusinessException(CodeMsg.USER_NOT_EXIST);
        }
        user.setRealName(userDto.getRealName());
        return repository.save(user);
    }

    @Override
    public AppUser getAndCheckByPhone(String phone) {
        if (StringUtils.isBlank(phone)) {
            throw new BusinessException(CodeMsg.MUST_BE_NOT_NULL, "缺少用户手机号");
        }
        AppUser user = getUserByPhone(phone);
        if (user == null) {
            throw new BusinessException(CodeMsg.USER_NOT_EXIST);
        }
        if (WZCL.STATE.IS_DELETE.equals(user.getState())) {
            throw new BusinessException(CodeMsg.USER_IS_DELETE);
        }
        if (!WZCL.USER_STATE.EFFECTIVE.equals(user.getUserState())) {
            throw new BusinessException(CodeMsg.USER_NOT_EFFECTIVE);
        }
        return user;
    }

    @Override
    public AppUser getAndCheckById(Integer id) {
        if (id == null) {
            throw new BusinessException(CodeMsg.MUST_BE_NOT_NULL, "缺少用户Id");
        }
        AppUser user = getUserById(id);
        if (user == null) {
            throw new BusinessException(CodeMsg.USER_NOT_EXIST);
        }
        if (WZCL.STATE.IS_DELETE.equals(user.getState())) {
            throw new BusinessException(CodeMsg.USER_IS_DELETE);
        }
        if (!WZCL.USER_STATE.EFFECTIVE.equals(user.getUserState())) {
            throw new BusinessException(CodeMsg.USER_NOT_EFFECTIVE);
        }
        return user;
    }

    @Override
    public AppUser updateAdminUser(UserDto userDto) {
        if (userDto == null || userDto.getId() == null) {
            throw new BusinessException(CodeMsg.MUST_BE_NOT_NULL, "缺少用户Id");
        }
        AppUser user = getUserById(userDto.getId());
        if (user == null) {
            throw new BusinessException(CodeMsg.USER_NOT_EXIST);
        }
        BeanUtils.copyProperties(userDto, user, "id", "phone", "state", "password", "userState", "type");
        //详情
        if (userDto.getUserInfoDto() != null) {
            UserInfo userInfo = userInfoService.updateUserInfo(userDto.getUserInfoDto());
            user.setUserInfo(userInfo);
        }
        //修改年级
        if (userDto.getGradeId() != null && (user.getGrade() == null || !userDto.getGradeId().equals(user.getGrade().getId()))) {
            Grade grade = gradeService.getGradeById(userDto.getGradeId());
            if (grade == null) {
                throw new BusinessException(CodeMsg.GRADE_NOT_EXIST);
            }
            user.setGrade(grade);
        }
        //修改真实姓名
        if (StringUtils.isBlank(userDto.getRealName())) {
            user.setRealName(userDto.getRealName());
        }
        //修改权限(同时角色)
        if (userDto.getRoleId() != null) {
            List<AppRole> roleList = user.getRoleList();
            System.out.println("角色组："+roleList.size());
            //用户的权限发生了改变
            if (!roleList.get(0).getId().equals(userDto.getRoleId())) {
                updateUserRole(userDto.getRoleId(), user);
            }
        }
        AppUser save = repository.save(user);
        //老师用户同步更新课程老师数据
        if (WZCL.USER_TYPE.TEACHER.equals(save.getType())) {
            courseTeacherService.refreshTeacher(save);
        }
        return save;
    }

    @Override
    public void delUserByPhone(String phone) {
        AppUser user = getAndCheckByPhone(phone);
        user.setState(WZCL.STATE.IS_DELETE);
        repository.save(user);
        log.info("AppUser:{} logic deletion", user.getId());
    }


    public void updateUserRole(Integer roleId, AppUser user) {
        ArrayList<AppRole> roles = new ArrayList<>();
        AppRole appRole = roleRepository.findById(roleId).orElse(null);
        if (appRole != null) {
            switch (appRole.getName()) {
                case "ROLE_ADMIN":
                    roles.add(appRole);
                    user.setType(WZCL.USER_TYPE.ADMIN);
                    break;
                case "ROLE_TEACHER":
                    roles.add(appRole);
                    user.setType(WZCL.USER_TYPE.TEACHER);
                    break;
                case "ROLE_STUDENT":
                    roles.add(appRole);
                    user.setType(WZCL.USER_TYPE.STUDENT);
                    break;
                default:
                    appRole = roleRepository.findByName("ROLE_STUDENT");
                    roles.add(appRole);
                    user.setType(WZCL.USER_TYPE.STUDENT);
                    user.setRoleList(roles);
            }
        }
        user.setRoleList(roles);
    }


    @Override
    public AppUser changeUserState(UserDto userDto) {
        if (userDto.getUserState() == null) {
            throw new BusinessException(CodeMsg.MUST_BE_NOT_NULL, "缺少用户状态");
        }
        if (userDto.getPhone() == null) {
            throw new BusinessException(CodeMsg.MUST_BE_NOT_NULL, "缺少用户账号");
        }
        AppUser user = getUserByPhone(userDto.getPhone());
        if (user == null) {
            throw new BusinessException(CodeMsg.USER_NOT_EXIST);
        }
        if (!user.getUserState().equals(userDto.getUserState())) {
            if (WZCL.USER_STATE.EFFECTIVE.equals(userDto.getUserState())) {
                //解封
                user.setUserState(WZCL.USER_STATE.EFFECTIVE);
            } else if (WZCL.USER_STATE.INVALID.equals(userDto.getUserState())) {
                //禁封
                user.setUserState(WZCL.USER_STATE.INVALID);
            } else {
                throw new BusinessException(CodeMsg.USER_STATE_ERROR);
            }
            repository.save(user);
        }

        return user;
    }


    private Specification<AppUser> getSpecification(UserDto userDto) {
        return new Specification<AppUser>() {
            @Override
            public Predicate toPredicate(Root<AppUser> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicates = new ArrayList<Predicate>();
                if (StringUtils.isNotBlank(userDto.getPhone())) {
                    predicates.add(criteriaBuilder.like(root.get("phone"), "%" + userDto.getPhone() + "%"));
                }
                if (StringUtils.isNotBlank(userDto.getRealName())) {
                    predicates.add(criteriaBuilder.like(root.get("realName"), "%" + userDto.getRealName() + "%"));
                }
                if (userDto.getUserState() != null) {
                    predicates.add(criteriaBuilder.equal(root.get("userState"), userDto.getUserState()));
                }
                if (userDto.getType() != null) {
                    predicates.add(criteriaBuilder.equal(root.get("type"), userDto.getType()));
                }
                predicates.add(criteriaBuilder.equal(root.get("state"), WZCL.STATE.NOT_DELETE));
                return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
            }
        };
    }

    //生成随机用户名，数字和字母组成,
    public String getStringRandom(int length) {
        StringBuilder val = new StringBuilder();
        Random random = new Random();

        //参数length，表示生成几位随机数
        for (int i = 0; i < length; i++) {
            String charOrNum = random.nextInt(2) % 2 == 0 ? "char" : "num";
            //输出字母还是数字
            if ("char".equalsIgnoreCase(charOrNum)) {
                //输出是大写字母还是小写字母
                int temp = random.nextInt(2) % 2 == 0 ? 65 : 97;
                val.append((char) (random.nextInt(26) + temp));
            } else {
                val.append(String.valueOf(random.nextInt(10)));
            }
        }
        return val.toString();
    }

}
